#ifndef CONIN_COMPILER_PROGRAM_DATABASE_IMPLEMENTATION_H
#define CONIN_COMPILER_PROGRAM_DATABASE_IMPLEMENTATION_H

#include "progdb.h"
#include <list>
#include <fstream>
#include <dirent.h>

namespace cnc {

	namespace compiler {

		class ProgramDatabaseImpl : public ProgramDatabase, public ProgramManager
		{
			std::string path_;
			std::list<ProgramData> listing_;
			std::list<ProgramData>::iterator it;
			bool generateListing()
			{
				DIR *dp;
				struct dirent *ep;
				dp = opendir(path_.c_str());
				if (dp == NULL)
					return false;
				listing_.empty();
				while ((ep = readdir(dp)) != NULL)
				listing_.push_back(ProgramData(path_ + ep->d_name));
				closedir(dp);
				return true;
			}
		public:
			static ProgramDatabaseImpl &instance()
			{
				static ProgramDatabaseImpl object("");
				return object;
			}
			virtual ProgramManager *getProgramManager()
			{
				return this;
			}	
		private:
			ProgramDatabaseImpl(const char *path) : path_(path)
			{
			}
			void setPath(const char *path)
			{
				path_ = path;
			}
			ProgramData *getFirstProgramData()
			{
				generateListing();
				it = listing_.begin();
				return &(*it);
			}
			ProgramData *getNextProgramData()
			{
				it++;
				if (it == listing_.end())
					return 0;
				else
					return &(*it);
			}
			std::istream *getInputStream(const char *name)
			{
				std::string fullpath = path_ + name;
				return new std::ifstream(fullpath.c_str());
			}
			void releaseInputStream(std::istream *is)
			{
				dynamic_cast<std::ifstream *>(is)->close();
				delete dynamic_cast<std::ifstream *>(is);
			}
			std::ostream *getOutputStream(const char *name)
			{
				std::string fullpath = path_ + name;
				return new std::ofstream(fullpath.c_str());
			}
			void releaseOutputStream(std::ostream *os)
			{
				dynamic_cast<std::ofstream *>(os)->close();
				delete dynamic_cast<std::ostream *>(os);
			}
			bool renameProgram(const char *oldname, const char *newname)
			{
				if (rename((path_ + oldname).c_str(), (path_ + newname).c_str()) == 0)
					return true;
				else
					return false;
			}
			bool removeProgram(const char *filename)
			{
				if (remove((path_ + filename).c_str()) == 0)
					return true;
				else
					return false;
			}
			void copyProgram(const char *copyFilename, const char *sourceFilename)
			{
				std::ifstream infile((path_ + sourceFilename).c_str(), std::ios_base::binary);
				std::ofstream outfile((path_ + copyFilename).c_str(), std::ios_base::binary);
				outfile << infile.rdbuf();
			}
		};

	} // namespace compiler

} // namespace cnc

#endif

